// Copyright 叶湘 ( weixin:yexiang841, email:yexiang841@qq.com ), Shitouren Studio. All Rights Reserved.

#include "Hit/Q3D_CPPU_HitMode.h"
#include "Hit/Q3D_CPPU_Hit.h"
#include "Property/Q3D_CPPU_PropertyPLIPro.h"
#include "Logger/Q3D_CPPU_Logger.h"

void UQ3D_CPPU_HitModeBase::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Hit_Once;
    return;
}

void UQ3D_CPPU_HitModeBase::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    bool_success = false;
    string_log = "No_Implementation";
    return;
}

void UQ3D_CPPU_HitModeBase::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    bool_success = false;
    string_log = "No_Implementation";
    return;
}

void UQ3D_CPPU_HitModeHitOnce::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Hit_Once;
    return;
}

void UQ3D_CPPU_HitModeHitOnce::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!ptr_u_property_pli_pro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    switch (this->Ptr_U_Hit->Q3D_F_HitType_GetEnum())
    {
    case EQ3D_CPPE_HitType::Damage:
        ptr_u_property_pli_pro->Q3D_F_Value_Dec(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    case EQ3D_CPPE_HitType::Recover:
        ptr_u_property_pli_pro->Q3D_F_Value_Inc(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    default:
        break;
    }
    this->Ptr_U_Hit->Q3D_ED_Hit_Once.Broadcast(this->Ptr_U_Hit);
    this->Ptr_U_Hit->Q3D_ED_Hit_Done.Broadcast(this->Ptr_U_Hit);
    bool_success = true;
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Done_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHitOnce::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    bool_success = true;
    string_log = "";
    return;
}

void UQ3D_CPPU_HitModeHitMultiple::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Hit_Multiple;
    return;
}

void UQ3D_CPPU_HitModeHitMultiple::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!ptr_u_property_pli_pro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    if (this->Int_HitCount <= 0)
    {
        bool_success = false;
        string_log = "Invalid_Int_HitCount";
        return;
    }
    if (this->Float_HitInterval <= 0)
    {
        bool_success = false;
        string_log = "Invalid_Float_HitInterval";
        return;
    }
    this->Ptr_U_PropertyPLIPro = ptr_u_property_pli_pro;
    this->Int_HitCountIter = this->Int_HitCount;
    this->_F_Hit_Execute();
    if (this->Int_HitCountIter <= 0)
    {
        bool_success = true;
        string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Done_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
        return;
    }
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // FTimerHandle TH_Hit_Executor;
    world->GetTimerManager().SetTimer(TH_Hit_Executor, this, &UQ3D_CPPU_HitModeHitMultiple::_F_Hit_Execute, this->Float_HitInterval, true);
    bool_success = true;
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Start_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHitMultiple::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // FTimerHandle TH_Hit_Executor;
    world->GetTimerManager().ClearTimer(TH_Hit_Executor);
    this->Int_HitCountIter = 0;
    this->Ptr_U_Hit->Q3D_ED_Hit_Cancel.Broadcast(this->Ptr_U_Hit);
    bool_success = true;
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Cancel_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHitMultiple::_F_Hit_Execute()
{
    // Q3D_LOG( Verbose, this->Ptr_U_Hit->Q3D_F_ToString() + "_Once" );
    switch (this->Ptr_U_Hit->Q3D_F_HitType_GetEnum())
    {
    case EQ3D_CPPE_HitType::Damage:
        this->Ptr_U_PropertyPLIPro->Q3D_F_Value_Dec(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    case EQ3D_CPPE_HitType::Recover:
        this->Ptr_U_PropertyPLIPro->Q3D_F_Value_Inc(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    default:
        break;
    }
    this->Ptr_U_Hit->Q3D_ED_Hit_Once.Broadcast(this->Ptr_U_Hit);
    this->Int_HitCountIter -= 1;
    if (this->Int_HitCountIter == 0)
    {
        UWorld *world = this->Ptr_U_Hit->GetWorld();
        if (world)
        {
            // FTimerHandle TH_Hit_Executor;
            world->GetTimerManager().ClearTimer(TH_Hit_Executor);
            this->Ptr_U_Hit->Q3D_ED_Hit_Done.Broadcast(this->Ptr_U_Hit);
        }
        return;
    }
    return;
}

void UQ3D_CPPU_HitModeHitInfinite::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Hit_Infinite;
    return;
}

void UQ3D_CPPU_HitModeHitInfinite::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!ptr_u_property_pli_pro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    if (this->Float_HitInterval <= 0)
    {
        bool_success = false;
        string_log = "Invalid_Float_HitInterval";
        return;
    }
    this->Ptr_U_PropertyPLIPro = ptr_u_property_pli_pro;
    this->_F_Hit_Execute();
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // FTimerHandle TH_Hit_Executor;
    world->GetTimerManager().SetTimer(TH_Hit_Executor, this, &UQ3D_CPPU_HitModeHitInfinite::_F_Hit_Execute, this->Float_HitInterval, true);
    bool_success = true;
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Start_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHitInfinite::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // FTimerHandle TH_Hit_Executor;
    world->GetTimerManager().ClearTimer(TH_Hit_Executor);
    this->Ptr_U_Hit->Q3D_ED_Hit_Cancel.Broadcast(this->Ptr_U_Hit);
    bool_success = true;
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Cancel_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHitInfinite::_F_Hit_Execute()
{
    // 真正执行一次命中
    switch (this->Ptr_U_Hit->Q3D_F_HitType_GetEnum())
    {
    case EQ3D_CPPE_HitType::Damage:
        this->Ptr_U_PropertyPLIPro->Q3D_F_Value_Dec(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    case EQ3D_CPPE_HitType::Recover:
        this->Ptr_U_PropertyPLIPro->Q3D_F_Value_Inc(this->Ptr_U_Hit->Q3D_F_HitValue_Get());
        break;
    default:
        break;
    }
    this->Ptr_U_Hit->Q3D_ED_Hit_Once.Broadcast(this->Ptr_U_Hit);
    return;
}

void UQ3D_CPPU_HitModeHaloConst::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Halo_Const;
    return;
}

void UQ3D_CPPU_HitModeHaloConst::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!ptr_u_property_pli_pro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    // 暂存属性
    this->Ptr_U_PropertyPLIPro = ptr_u_property_pli_pro;
    // 将 Hit 写入 Property
    this->Ptr_U_PropertyPLIPro->Q3D_F_HitHalo_Inc(this->Ptr_U_Hit, bool_success, string_log);
    // 写入不成功连同日志一起返回(只有一个原因就是 HitMode 不是 Halo)
    if (!bool_success)
    {
        return;
    }
    // 写入成功拼个日志，此时理应在 Property 中触发了 ValuePro_Reset 事件
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Start_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHaloConst::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!this->Ptr_U_PropertyPLIPro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    this->Ptr_U_PropertyPLIPro->Q3D_F_HitHalo_Dec(this->Ptr_U_Hit->Name_Id, this->Ptr_U_Hit->Q3D_F_HitType_GetEnum(), bool_success, string_log);
    if (!bool_success)
    {
        return;
    }
    this->Ptr_U_Hit->Q3D_ED_Halo_Cancel.Broadcast(this->Ptr_U_Hit);
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Cancel_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHaloTimed::Q3D_F_HitMode_GetEnum(EQ3D_CPPE_HitMode &enum_hit_mode) const
{
    enum_hit_mode = EQ3D_CPPE_HitMode::Halo_Timed;
    return;
}

void UQ3D_CPPU_HitModeHaloTimed::Q3D_F_Hit_Execute(UQ3D_CPPU_PropertyPLIPro *ptr_u_property_pli_pro, bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!ptr_u_property_pli_pro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // 暂存属性
    this->Ptr_U_PropertyPLIPro = ptr_u_property_pli_pro;
    // 将 Hit 写入 Property
    this->Ptr_U_PropertyPLIPro->Q3D_F_HitHalo_Inc(this->Ptr_U_Hit, bool_success, string_log);
    // 写入不成功连同日志一起返回(只有一个原因就是 HitMode 不是 Halo)
    if (!bool_success)
    {
        return;
    }
    // FTimerHandle TH_Halo_Terminator;
    world->GetTimerManager().SetTimer(TH_Halo_Terminator, this, &UQ3D_CPPU_HitModeHaloTimed::_F_Hit_Cancel, this->Float_HaloTime, false);
    // 写入成功拼个日志，此时理应在 Property 中触发了 ValuePro_Reset 事件
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Start_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHaloTimed::Q3D_F_Hit_Cancel(bool &bool_success, FString &string_log)
{
    // 参数检查
    if (!this->Ptr_U_Hit)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_Hit";
        return;
    }
    if (!this->Ptr_U_PropertyPLIPro)
    {
        bool_success = false;
        string_log = "Invalid_Ptr_U_PropertyPLIPro";
        return;
    }
    this->Ptr_U_PropertyPLIPro->Q3D_F_HitHalo_Dec(this->Ptr_U_Hit->Name_Id, this->Ptr_U_Hit->Q3D_F_HitType_GetEnum(), bool_success, string_log);
    if (!bool_success)
    {
        return;
    }
    UWorld *world = this->Ptr_U_Hit->GetWorld();
    if (!world)
    {
        bool_success = false;
        string_log = "Q3D_Hit_Need_Setting_At_Least_1_AActor_Within(Outer/Maker/Causer/Target)_To_Perform_Timer";
        return;
    }
    // FTimerHandle TH_Halo_Terminator;
    world->GetTimerManager().ClearTimer(TH_Halo_Terminator);
    this->Ptr_U_Hit->Q3D_ED_Halo_Done.Broadcast(this->Ptr_U_Hit);
    string_log = this->Ptr_U_Hit->Q3D_F_ToString() + "_Cancel_To_[" + this->Ptr_U_Hit->Ptr_A_HitTarget->GetName() + "]";
    return;
}

void UQ3D_CPPU_HitModeHaloTimed::_F_Hit_Cancel()
{
    bool bool_success;
    FString string_log;
    this->Q3D_F_Hit_Cancel(bool_success, string_log);
    if (!bool_success)
    {
        Q3D_LOG(Error, string_log);
    }
    return;
}
